package com.haotian.mail.client;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import com.haotian.mail.config._EmailPOP3Config;
import com.haotian.mail.exception._EmailPOP3Exception;

/**
 * @author 张昊天<494009061@QQ.COM> <br>
 */
public class _EmailPOP3Client implements AutoCloseable {

	private Socket socket;
	private BufferedReader reader;
	private BufferedWriter writer;
	private _EmailPOP3Config config;
	private String message;
	private StringBuilder buffer = new StringBuilder();

	public _EmailPOP3Client(_EmailPOP3Config config) throws IOException, _EmailPOP3Exception {
		this.config = config;
		if (config == null) {
			throw new _EmailPOP3Exception("_EmailPOP3Config is empty");
		}
		if (config.account == null || config.host == null || config.password == null || config.port == 0) {
			throw new _EmailPOP3Exception("The parameter in _EmailPOP3Config is empty");
		}
	}

	/**
	 * 连接并登录服务器
	 * 
	 * @return
	 * @throws IOException
	 * @throws _EmailPOP3Exception
	 */
	public _EmailPOP3Client connection() throws IOException, _EmailPOP3Exception {
		socket = new Socket();
		socket.connect(new InetSocketAddress(config.host, config.port), config.timeout);
		socket.setSoTimeout(config.soTimeout);
		
		// 初始化 字符缓冲流reader 和 writer
		reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

		String readStr = reader.readLine(); // 校验socket连接结果
		if (readStr == null || readStr.toUpperCase().indexOf("+OK") == -1) {
			throw new _EmailPOP3Exception(readStr);
		}
		// 登录用户
		this.sendCommand("user " + config.account);
		// 密码
		this.sendCommand("pass " + config.password);
		// 读取结果
		return this;
	}

	/**
	 * 发送命令
	 * 
	 * @param command
	 *            命令字符串
	 * @throws IOException
	 * @throws _EmailPOP3Exception
	 */
	private void sendCommand(String command) throws IOException, _EmailPOP3Exception {

		if (socket == null)
			connection();

		writer.write(command);
		writer.write("\r\n");
		writer.flush();
		String readStr = reader.readLine();

		// 判断结果是否为不OK
		if (readStr == null || readStr.toUpperCase().indexOf("+OK") == -1) {
			throw new _EmailPOP3Exception(readStr);
		}

	}
	

	/**
	 * 发送命令后读取结果
	 * 
	 * @throws IOException
	 * @throws _EmailPOP3Exception
	 */
	private void readerMessage() throws IOException, _EmailPOP3Exception {
		// 初始化字符串缓冲
		this.buffer.setLength(0);

		this.message = null;

		String tmp = null;

		while ((tmp = reader.readLine()) != null) {
			if (StringUtils.equals(tmp, "."))
				break;
			buffer.append(tmp).append("\r\n");
		}
		buffer.setLength(buffer.length()-2);
		// 最终获取缓冲中的消息 如果缓存中没有消息 那么 为""空字符串 而不是null
		this.message = buffer.toString();
	}

	/**
	 * 获取邮件id列表 列表ID按个数排列 1234567
	 * 
	 * @return
	 * @throws _EmailPOP3Exception
	 * @throws IOException
	 */
	public List<String> LIST() throws IOException, _EmailPOP3Exception {
		this.sendCommand("list");
		this.readerMessage();
		return Arrays.asList(message.split("/r/n"));

	}

	/**
	 * 获取完整邮件头
	 * 
	 * @param mailId
	 * @return
	 * @throws _EmailPOP3Exception
	 * @throws IOException
	 */
	public String TOP(String mailId) throws IOException, _EmailPOP3Exception {
		this.sendCommand("top " + mailId + " 0");
		this.readerMessage();
		return this.message;
	}

	/**
	 * 获取完整邮件
	 * 
	 * @param mailId
	 * @return
	 * @throws _EmailPOP3Exception
	 * @throws IOException
	 */
	public String RETR(String mailId) throws IOException, _EmailPOP3Exception {
		this.sendCommand("RETR " + mailId);
		this.readerMessage();
		return this.message;
	}

	/**
	 * 删除指定邮件
	 * 
	 * @param mailId
	 * @return
	 * @throws _EmailPOP3Exception
	 * @throws IOException
	 */
	public void DELE(String mailId) throws IOException, _EmailPOP3Exception {
		this.sendCommand("DELE " + mailId);
	}

	/**
	 * 查看邮件数量
	 * 
	 * @return
	 * @throws IOException
	 * @throws _EmailPOP3Exception
	 */
	public int STAT() throws IOException, _EmailPOP3Exception {

		if (socket == null)
			connection();

		writer.write("stat");

		writer.write("\r\n");

		writer.flush();

		String readStr = reader.readLine();

		// 判断结果是否为不OK
		if (readStr == null || readStr.toUpperCase().indexOf("+OK") == -1) {
			throw new _EmailPOP3Exception(readStr);
		}

		String[] split = readStr.split(" ");
		if (split.length > 1)
			return Integer.valueOf(split[1]);

		throw new _EmailPOP3Exception(readStr);
	}

	/**
	 * 退出
	 * 
	 * @return
	 * @throws _EmailPOP3Exception
	 * @throws IOException
	 */
	public void QUIT() throws IOException, _EmailPOP3Exception {
		this.sendCommand("QUIT");
	}

	@Override
	public void close() throws Exception {
		if (socket != null) {
			this.reader.close();
			this.writer.close();
			this.socket.close();
		}
	}

}
